﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using LTorrent.Torrent.BEncode;
using LTorrent.Torrent.File;


namespace LTorrent.Torrent
{  



   public struct FilesInf
   {
      public UInt64 length;
       public List<string> path;
    }

   class TorrentStruct
   {
       public string announce = "";//Анонс
       public List<string> announceList;//список трекеров
       public string comment = "";//комментарий
       public string createdBy = "";//информация о создателе
       public string creationDate = "";//Время
        public List<FilesInf> Files = null;//файлы (и пути)
        public UInt64 length = 0;
        public string name;//имя папки\торрента
        public uint pieceLen;//длина 
        public byte[] pieces;//части sha1 (20)
        public byte[] info_hash = null;

       public void ChangeAnnounce(int Index)
        {
            string Temp = announce;
            announce = announceList[Index];
            announceList[Index] = Temp;
        }
       
       protected void GetAnList(BElement Item)
       {//Список трекеров (рекурсия)
           for (int index = 0; index < Item.LSTItem.Count; index++)
               if (Item.LSTItem[index].STDItem != null)
                   announceList.Add(Item.LSTItem[index].ToString());
               else
                   if (Item.LSTItem[index].LSTItem != null)
                       GetAnList(Item.LSTItem[index]);
                   else throw new Exception("Неверный торрент файл!");
       }

       protected void AccumFiles(BDictionary Dict)
       {
           FilesInf NewFile = new FilesInf();
           for (int index = 0; Dict.Count > index; index++)
           {
               BElement[] Item = Dict[index];
               if (Item[0].ToString() == "length")
               {
                   NewFile.length = uint.Parse(Item[1].ToString());
               }
               if (Item[0].ToString() == "path")
               {
                   NewFile.path = new List<string>();
                   for (int i = 0; i<Item[1].LSTItem.Count; i++)
                   {
                       NewFile.path.Add(Item[1].LSTItem[i].ToString());
                   }
               }
           }
           Files.Add(NewFile);
       }

       protected void AccumulateInfo(BDictionary Dict)
       {
           for (int index = 0; index < Dict.Count; index++)
           {
               BElement[] Item = Dict[index];
               if (Item[0].ToString() == "length")
               {//один файл
                   length = uint.Parse(Item[1].ToString());
               }            
               if (Item[0].ToString() == "name")
               {
                   name = Item[1].ToString();
               }
               if (Item[0].ToString() == "piece length")
               {
                   pieceLen = uint.Parse(Item[1].ToString());
               }
               if (Item[0].ToString() == "pieces")
               {
                   pieces = Item[1].STDItem.GETvalue;
               }
               if (Item[0].ToString() == "files")
               {//Несколько файлов
                   Files = new List<FilesInf>();
                   for (int i = 0; i < Item[1].LSTItem.Count; i++)
                   {
                       AccumFiles(Item[1].LSTItem[i].DICItem);//обработка i-го файла.
                   }
               }
           }
       }

       public TorrentStruct(string TorrentPath)
       {//Конструктор. - все вызовы - через него
           FileBEncoding BEncode = new FileBEncoding(TorrentPath);
           BElement X = BEncode.BenItems[0];
           if (X == null || X.DICItem == null)
               throw new Exception("Поврежденный торрент");
           try
           {
               for (int index = 0; index < X.DICItem.Count; index++)
               {
                   BElement[] Item = X.DICItem[index];
                   if (Item[0].ToString() == "announce")
                   {
                       announce = Item[1].ToString();
                   }
                   if (Item[0].ToString() == "announce-list")
                   {
                       announceList = new List<string>();
                       GetAnList(Item[1]);
                   }
                   if (Item[0].ToString() == "comment")
                   {
                       comment = Item[1].ToString();
                   }
                   if (Item[0].ToString() == "created by")
                   {
                       createdBy = Item[1].ToString();
                   }
                   if (Item[0].ToString() == "creation date")
                   {
                       creationDate = Item[1].ToString();
                   }
                   if (Item[0].ToString() == "info")
                   {
                       //pЗдесь получаем список фалов и их длину
                       AccumulateInfo(Item[1].DICItem);

                       //Вычисляем info_hash
                       
                       using (var MemStrm = new MemoryStream())
                       {
                           using (BinaryWriter outWriter = new BinaryWriter(MemStrm, Encoding.ASCII))
                           {//Сериализация в MemoryStream через BinaryWriter
                              // Item[0].Serialize(outWriter);//ключ
                               Item[1].Serialize(outWriter);//значение ключа
                               
                           }
                           byte[] ContentToHash = MemStrm.ToArray();
                           //Вычисление SHA1
                           SHA1Managed sha1 = new SHA1Managed();
                           info_hash = sha1.ComputeHash(ContentToHash);
                       }
                   }
       
                
                   
               }
           }
           catch (Exception Err)
           {
               Console.WriteLine(Err.Message);
           }
           if (length == 0)
           {
               //Files.ForEach(X => length += X.length);
               foreach (var x in Files)
               {
                   length += x.length;
                }
           }
       }
    }
}
